/****************************************************************************
 * Elisa 1.0                                                                *
 *--------------------------------------------------------------------------*
 * Author: Laurent Granvilliers, Vincent Sorin                              *
 * Copyright (c) 2004 Laboratoire d'Informatique de Nantes Atlantique       *
 *--------------------------------------------------------------------------*
 * Elisa is distributed WITHOUT ANY WARRANTY. Read the associated           *
 * COPYRIGHT file for more details.                                         *
 *--------------------------------------------------------------------------*
 * elisa_realexpr.h                                                         *
 ****************************************************************************/



#ifndef _elisa_real_expr_h_
#define _elisa_real_expr_h_


#include <iostream>
#include <vector>
#include <string>

#include "elisa_defs.h"
#include "elisa_domain.h"
#include "elisa_real_var.h"
#include "elisa_int_var.h"
#include "elisa_real_constant.h"
#include "elisa_variable.h"
#include "elisa_constant.h"
#include "elisa_expression.h"


NAMESPACE_ELISA


//---------------------
// Forward declarations
//---------------------
class RealExpr;
class RealExprVisitor;
class RealExprRep;
class RealExprRepConst;
class RealExprRepIntervalConst;
class RealExprRepVar;
class RealExprRepMin;
class RealExprRepMax;
class RealExprRepAbs;
class RealExprRepAdd;
class RealExprRepSum;
class RealExprRepMul;
class RealExprRepProd;
class RealExprRepSub;
class RealExprRepOpp;
class RealExprRepDiv;
class RealExprRepSqr;
class RealExprRepSqrt;
class RealExprRepPow;
class RealExprRepLog;
class RealExprRepExp;
class RealExprRepCos;
class RealExprRepCosh;
class RealExprRepACos;
class RealExprRepACosh;
class RealExprRepSin;
class RealExprRepSinh;
class RealExprRepASin;
class RealExprRepASinh;
class RealExprRepTan;
class RealExprRepTanh;
class RealExprRepATan;
class RealExprRepATanh;
class IntervalFormFactory;
//---------------------


/// @defgroup Expression Expression

/**
 * @ingroup Expression
 * @class RealExprRep
 * @brief Base class for the tree-representation of expressions
 * over real numbers
 */
class RealExprRep : public SymbolicExpressionRep
{
public:
	/**
 	 * Default constructor
 	 */
	RealExprRep ();

	/**
 	 * Copy construtor
 	 */
	RealExprRep (const RealExprRep & e);

	/**
 	 * Destructor
 	 */
	virtual
	~RealExprRep ();

	/**
 	 * the priority, which is used for printing
 	 * @return the priority
 	 */
	virtual int priority() const;

	/**
 	 * Return a copy of *this
 	 * @return a RealExprRep that is a copy
 	 */
	virtual RealExprRep *copy() const = 0;

	/// Visitor
	virtual void visit(RealExprVisitor & v) = 0;

	/**
 	 * @brief compute all variables of the expression in a set
 	 * @param s set where variables are putten
 	 */
	virtual void toVariables(VarImplSet & s);

	/**
 	 * @brief init the Intenal Representation of the variables
 	 * @param st SearchTree
 	 */
	virtual void initVariableImplementation(SearchTree & searchTree);

	/**
 	 * Return the number of occurrences of v in the expression
 	 * @param v the variable which we want the multiplicity
 	 * @return the multiplicity of v
 	 */
	virtual int multiplicity(VariableImpl & v);
};



/**
 * @ingroup Expression
 * @class RealExprVisitor
 * @brief Visitor of real expressions
 */
class RealExprVisitor
{
public:
	/// Constructor
	RealExprVisitor ();

	/// Destructor
	virtual
	~RealExprVisitor ();

	/// @name Visit of each expression type
	//@{
	/// Sends the visitor to the expression
	virtual void visit(RealExprRep & e);

	/// Call of the visitor from a constant expression
	virtual void visited(RealExprRepConst & e);

	/// Call of the visitor from an interval representing a constant
	virtual void visited(RealExprRepIntervalConst & e);

	/// Call of the visitor from an expression representing a variable
	virtual void visited(RealExprRepVar & e);

	/// Call of the visitor from an expression min(f,g)
	virtual void visited(RealExprRepMin & e);

	/// Call of the visitor from an expression max(f,g)
	virtual void visited(RealExprRepMax & e);

	/// Call of the visitor from an expression +(f,g)
	virtual void visited(RealExprRepAdd & e);

	/// Call of the visitor from an expression +(f1,f2,...,fN)
	virtual void visited(RealExprRepSum & e);

	/// Call of the visitor from an expression *(f,g)
	virtual void visited(RealExprRepMul & e);

	/// Call of the visitor from an expression *(f1,f2,...,fN)
	virtual void visited(RealExprRepProd & e);

	/// Call of the visitor from an expression -(f,g)
	virtual void visited(RealExprRepSub & e);

	/// Call of the visitor from an expression -f
	virtual void visited(RealExprRepOpp & e);

	/// Call of the visitor from an expression /(f,g)
	virtual void visited(RealExprRepDiv & e);

	/// Call of the visitor from an expression sqr(f)
	virtual void visited(RealExprRepSqr & e);

	/// Call of the visitor from an expression sqrt(f)
	virtual void visited(RealExprRepSqrt & e);

	/// Call of the visitor from an expression abs(f)
	virtual void visited(RealExprRepAbs & e);

	/// Call of the visitor from an expression pow(f,n)
	virtual void visited(RealExprRepPow & e);

	/// Call of the visitor from an expression log(f)
	virtual void visited(RealExprRepLog & e);

	/// Call of the visitor from an expression exp(f)
	virtual void visited(RealExprRepExp & e);

	/// Call of the visitor from an expression cos(f)
	virtual void visited(RealExprRepCos & e);

	/// Call of the visitor from an expression acos(f)
	virtual void visited(RealExprRepACos & e);

	/// Call of the visitor from an expression sin(f)
	virtual void visited(RealExprRepSin & e);

	/// Call of the visitor from an expression asin(f)
	virtual void visited(RealExprRepASin & e);

	/// Call of the visitor from an expression tan(f)
	virtual void visited(RealExprRepTan & e);

	/// Call of the visitor from an expression atan(f)
	virtual void visited(RealExprRepATan & e);

	/// Call of the visitor from an expression cos(f)
	virtual void visited(RealExprRepCosh & e);

	/// Call of the visitor from an expression acos(f)
	virtual void visited(RealExprRepACosh & e);

	/// Call of the visitor from an expression sin(f)
	virtual void visited(RealExprRepSinh & e);

	/// Call of the visitor from an expression asin(f)
	virtual void visited(RealExprRepASinh & e);

	/// Call of the visitor from an expression tan(f)
	virtual void visited(RealExprRepTanh & e);

	/// Call of the visitor from an expression atan(f)
	virtual void visited(RealExprRepATanh & e);
	//@}
};

/**
 * @ingroup Expression
 * @class ToVariableVisitor
 * @brief Visitor to compute the variable of the expression in a set
 */
class ToVariableVisitor : public RealExprVisitor
{
public:
	/// Constructor
	ToVariableVisitor (VarImplSet *s)
	{
		_s = s;
	}

	/// Destructor
	~ToVariableVisitor ()
	{
	}

	/// @name Visit of each expression type
	//@{
	/// Call of the visitor from an expression representing a variable
	void visited(RealExprRepVar & e);
	//@}

private:
	VarImplSet *_s;
};

/**
 * @ingroup Expression
 * @class initVariableImplementationVisitor
 * @brief Visitor to compute the variable of the expression in a set
 */
class initVariableImplementationVisitor : public RealExprVisitor
{
public:
	/// Constructor
	initVariableImplementationVisitor (SearchTree *st)
	{
		_st = st;
	}

	/// Destructor
	~initVariableImplementationVisitor ()
	{
	}

	/// @name Visit of each expression type
	//@{

	/// Call of the visitor from an expression representing a variable
	void visited(RealExprRepVar & e);
	//@}

private:
	SearchTree *_st;
};


/**
 * @ingroup Expression
 * @class MultiplicityVisitor
 * @brief Visitor to compute the multiplicity of a variable in an expression
 */
class MultiplicityVisitor : public RealExprVisitor
{
public:
	/// Constructor
	MultiplicityVisitor (const RealVarImpl & v)
	{
		_v = &v;
		_counter = 0;
	}

	/// Destructor
	~MultiplicityVisitor ()
	{
	}

	int getMultiplicity()
	{
		return _counter;
	}

	/// @name Visit of each expression type
	//@{
	/// Call of the visitor from an expression representing a variable
	void visited(RealExprRepVar & e);


	//@}

private:
	const RealVarImpl *_v;
	int _counter;
};


/**
 * @ingroup Expression
 * @class RealExprRepVar
 * @brief Tree-representation of variables
 */
class RealExprRepVar : public RealExprRep
{
public:
	/**
 	 * Constructor
 	 * @param v the RealVar used in the symbolic expression
 	 */
	RealExprRepVar (Variable & v);

	/**
 	 * Constructor
 	 * @param v the RealVar used in the symbolic expression
 	 */
	RealExprRepVar (Variable *v);

	/**
 	 * Copy constructor
 	 */
	RealExprRepVar (const RealExprRepVar & e);

	/**
 	 * Destructor
 	 */
	~RealExprRepVar ();

	/**
 	 * Copy operator
 	 */
	RealExprRepVar &
	operator=(const RealExprRepVar & e);

	/// @name Return the corresponding variable
	//@{
	Variable & variable();

	const Variable & variable() const;
	//@}

	/// @name Base class's virtual methods
	//@{
	int priority() const;

	RealExprRep *copy() const;

	void visit(RealExprVisitor & v);

	void print(std::ostream & os) const;

	//@}


private:
	Variable *_v; // the variable
};


/**
 * @ingroup Expression
 * @class RealExprRepConst
 * @brief Tree-representation of interval constants
 */
class RealExprRepConst : public RealExprRep
{
public:
	/**
 	 * Constructor
 	 * It builds a new constrep, but not the symbolic
 	 * representation
 	 * @param i the value of the constant
 	 */
	RealExprRepConst (double i);

	/**
 	 * Constructor
 	 * It builds a new constrep from the symbolic constant
 	 * @param c the symbolic constant
 	 */
	RealExprRepConst (const RealConstant & c);

	/**
 	 * Copy constructor
 	 */
	RealExprRepConst (const RealExprRepConst & e);

	/// Copy operator
	RealExprRepConst &
	operator=(const RealExprRepConst & e);

	/**
 	 * Destructor
 	 */
	~RealExprRepConst ();

	/**
 	 * Return the corresponding constant
 	 * @return an interval corresponding to the constant
 	 */
	double value() const;

	Interval getInterval() const;

	/// @name Base class's virtual methods
	//@{
	int priority() const;

	RealExprRep *copy() const;

	void visit(RealExprVisitor & v);

	void print(std::ostream & os) const;

	//@}
private:
	RealConstant _value;
};


/**
 * @ingroup Expression
 * @class RealExprRepIntervalConst
 * @brief Tree-representation of interval constants
 */
class RealExprRepIntervalConst : public RealExprRep
{
public:
	/**
 	 * Constructor
 	 * It builds a new constrep, but not the symbolic
 	 * representation
 	 * @param i the value of the constant
 	 */
	RealExprRepIntervalConst (double i, double s);

	/**
 	 * Constructor
 	 * It builds a new constrep from the symbolic constant
 	 * @param c the symbolic constant
 	 */
	RealExprRepIntervalConst (const IntervalConstant & c);

	/**
 	 * Copy constructor
 	 */
	RealExprRepIntervalConst (const RealExprRepIntervalConst & e);

	/// Copy operator
	RealExprRepIntervalConst &
	operator=(const RealExprRepIntervalConst & e);

	/**
 	 * Destructor
 	 */
	~RealExprRepIntervalConst ();

	/**
 	 * Return the corresponding constant
 	 * @return an interval corresponding to the bound inf
 	 */
	double inf() const;

	/**
 	 * Return the corresponding constant
 	 * @return an interval corresponding to the bound sup
 	 */
	double sup() const;

	Interval getInterval() const;

	/// @name Base class's virtual methods
	//@{
	int priority() const;

	RealExprRep *copy() const;

	void visit(RealExprVisitor & v);

	void print(std::ostream & os) const;

	//@}
private:
	IntervalConstant _value;
};


/**
 * @ingroup Expression
 * @class RealExprRepOp
 * @brief Tree-representation of operations
 */
class RealExprRepOp : public RealExprRep
{
public:
	/**
 	 * Constructor
 	 * @param op string that contains the operator  (used for printing)
 	 * @param priority the priority of the operator
 	 * @param prefix true if the operator is prefixed
 	 */
	RealExprRepOp (const std::string & op,
	               int priority,
	               bool prefix);

	/**
 	 * Destructor
 	 */
	//virtual
	~RealExprRepOp ();

	/**
 	 * Adds a new child in the last position
 	 * @param e the child to add
 	 */
	void addChild(RealExprRep *e);

	/**
 	 * Arity of the operator
 	 * @return the arity of the operator
 	 */
	int arity() const;

	/**
 	 * Access to children
 	 * @pre 1 <= i <= arity()
 	 * @return the i-th child
 	 */
	RealExprRep *child(int i);

	/**
 	 * Access to children
 	 * @pre 1 <= i <= arity()
 	 * @return the i-th child
 	 */
	RealExprRep *const_child(int i) const;

	/// @name Base class's virtual methods
	//@{
	virtual void print(std::ostream & os) const;

	int priority() const;
	//@}

protected:
	//typedef boost::shared_ptr<RealExprRep> RealExprRepPtr;
	std::vector<RealExprRep *> _exprs; // vector of children
	std::string _op;                  // operation symbol
	bool _prefix;                     // true for prefix operations
	int _priority;                    // priority for printing
};


/**
 * @ingroup Expression
 * @class RealExprRepBinaryOp
 * @brief Tree-representation of binary operations
 */
class RealExprRepBinaryOp : public RealExprRepOp
{
public:
	/**
 	 * Constructor
 	 * @param l left term of the operator
 	 * @param r rigt term of the operator
 	 * @param op string the containt the operator (for printing)
 	 * @param priority the priority of the operator
 	 */
	RealExprRepBinaryOp (RealExprRep *l,
	                     RealExprRep *r,
	                     const std::string & op,
	                     int priority);

	/**
 	 * Destructor
 	 */
	virtual
	~RealExprRepBinaryOp ();

	/// @name Access to the left and right expressions
	//@{
	RealExprRep *left();

	RealExprRep *const_left() const;

	RealExprRep *right();

	RealExprRep *const_right() const;
	//@}
};


/**
 * @ingroup Expression
 * @class RealExprRepUnaryOp
 * @brief Tree-representation of unary operations
 */
class RealExprRepUnaryOp : public RealExprRepOp
{
public:
	/// Constructor
	RealExprRepUnaryOp (RealExprRep *c,
	                    const std::string & op,
	                    int priority);

	/// Destructor
	virtual
	~RealExprRepUnaryOp ();

	/// @name Access to the child
	//@{
	RealExprRep *child();

	RealExprRep *const_child() const;
	//@}
};



/**
 * @ingroup Expression
 * @class RealExprRepMin
 * @brief Tree-representation of expressions min(left,right)
 */
class RealExprRepMin : public RealExprRepBinaryOp
{
public:
	/**
 	 * Constructor
 	 * @param l left sub-term
 	 * @param r right sub-term
 	 */
	RealExprRepMin (RealExprRep & l,
	                RealExprRep & r);

	/**
 	 * Constructor
 	 * @param l left sub-term
 	 * @param r right sub-term
 	 */
	RealExprRepMin (RealExprRep *l,
	                RealExprRep *r);

	/**
 	 * Copy constructor
 	 */
	RealExprRepMin (const RealExprRepMin & e);

	/**
 	 * Destructor
 	 */
	~RealExprRepMin();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepMin &
	operator=(const RealExprRepMin & e);
};
//

/**
 * @ingroup Expression
 * @class RealExprRepMin
 * @brief Tree-representation of expressions max(left,right)
 */
class RealExprRepMax : public RealExprRepBinaryOp
{
public:
	/**
 	 * Constructor
 	 * @param l left sub-term
 	 * @param r right sub-term
 	 */
	RealExprRepMax (RealExprRep & l,
	                RealExprRep & r);

	/**
 	 * Constructor
 	 * @param l left sub-term
 	 * @param r right sub-term
 	 */
	RealExprRepMax (RealExprRep *l,
	                RealExprRep *r);

	/**
 	 * Copy constructor
 	 */
	RealExprRepMax (const RealExprRepMax & e);

	/**
 	 * Destructor
 	 */
	~RealExprRepMax();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepMax &
	operator=(const RealExprRepMax & e);
};
//

/**
 * @ingroup Expression
 * @class RealExprRepAdd
 * @brief Tree-representation of expressions (left + right)
 */
class RealExprRepAdd : public RealExprRepBinaryOp
{
public:
	/**
 	 * Constructor
 	 * @param l left sub-term
 	 * @param r right sub-term
 	 */
	RealExprRepAdd (RealExprRep & l,
	                RealExprRep & r);

	/**
 	 * Constructor
 	 * @param l left sub-term
 	 * @param r right sub-term
 	 */
	RealExprRepAdd (RealExprRep *l,
	                RealExprRep *r);

	/**
 	 * Copy constructor
 	 */
	RealExprRepAdd (const RealExprRepAdd & e);

	/**
 	 * Destructor
 	 */
	~RealExprRepAdd();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepAdd &
	operator=(const RealExprRepAdd & e);
};



/**
 * @ingroup Expression
 * @class RealExprRepSum
 * @brief Tree-representation of expressions e1 + e2 + ... + eN (N>2)
 */
class RealExprRepSum : public RealExprRepOp
{
public:
	/// Constructor
	RealExprRepSum ();

	/// Destructor
	~RealExprRepSum ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepSum &
	operator=(const RealExprRepSum & e);
};



/**
 * @ingroup Expression
 * @class RealExprRepMul
 * @brief Tree-representation of expressions (left * right)
 */
class RealExprRepMul : public RealExprRepBinaryOp
{
public:
	/**
 	 * Constructor
 	 * @param l left sub-term
 	 * @param r right sub-term
 	 */
	RealExprRepMul (RealExprRep & l,
	                RealExprRep & r);

	/**
 	 * Constructor
 	 * @param l left sub-term
 	 * @param r right sub-term
 	 */
	RealExprRepMul (RealExprRep *l,
	                RealExprRep *r);

	/**
 	 * Copy constructor
 	 */
	RealExprRepMul (const RealExprRepMul & e);

	/**
 	 * Destructor
 	 */
	~RealExprRepMul ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepMul &
	operator=(const RealExprRepMul & e);
};



/**
 * @ingroup Expression
 * @class RealExprRepProd
 * @brief Tree-representation of expressions e1 * e2 * ... * eN (N>2)
 */
class RealExprRepProd : public RealExprRepOp
{
public:
	/**
 	 * Constructor
 	 */
	RealExprRepProd ();

	/**
 	 * Destructor
 	 */
	~RealExprRepProd ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepProd &
	operator=(const RealExprRepProd & e);
};



/**
 * @ingroup Expression
 * @class RealExprRepSub
 * @brief Tree-representation of expressions (left - right)
 */
class RealExprRepSub : public RealExprRepBinaryOp
{
public:
	/**
 	 * Constructor
 	 * @param l left sub-term
 	 * @param r right sub-term
 	 */
	RealExprRepSub (RealExprRep & l,
	                RealExprRep & r);

	/**
 	 * Constructor
 	 * @param l left sub-term
 	 * @param r right sub-term
 	 */
	RealExprRepSub (RealExprRep *l,
	                RealExprRep *r);

	/**
 	 * Copy constructor
 	 */
	RealExprRepSub (const RealExprRepSub & e);

	/// Destructor
	~RealExprRepSub ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepSub &
	operator=(const RealExprRepSub & e);
};


/**
 * @ingroup Expression
 * @class RealExprRepOpp
 * @brief Tree-representation of expressions -e
 */
class RealExprRepOpp : public RealExprRepUnaryOp
{
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepOpp (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepOpp (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepOpp (const RealExprRepOpp & e);

	/// Destructor
	~RealExprRepOpp ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepOpp &
	operator=(const RealExprRepOpp & e);
};



/**
 * @ingroup Expression
 * @class RealExprRepDiv
 * @brief Tree-representation of expressions (left / right)
 */
class RealExprRepDiv : public RealExprRepBinaryOp
{
public:
	/**
 	 * Constructor
 	 * @param l left sub-term
 	 * @param r right sub-term
 	 */
	RealExprRepDiv (RealExprRep & l,
	                RealExprRep & r);

	/**
 	 * Constructor
 	 * @param l left sub-term
 	 * @param r right sub-term
 	 */
	RealExprRepDiv (RealExprRep *l,
	                RealExprRep *r);

	/**
 	 * Copy constructor
 	 */
	RealExprRepDiv (const RealExprRepDiv & e);

	/// Destructor
	~RealExprRepDiv ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepDiv &
	operator=(const RealExprRepDiv & e);
};

/**
 * @ingroup Expression
 * @class RealExprRepSqr
 * @brief Tree-representation of expressions sqr(e)
 */
class RealExprRepSqr : public RealExprRepUnaryOp
{
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepSqr (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepSqr (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepSqr (const RealExprRepSqr & e);

	/// Destructor
	~RealExprRepSqr ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepSqr &
	operator=(const RealExprRepSqr & e);
};



/**
 * @ingroup Expression
 * @class RealExprRepSqrt
 * @brief Tree-representation of expressions sqrt(e)
 */
class RealExprRepSqrt : public RealExprRepUnaryOp {
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepSqrt (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepSqrt (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepSqrt (const RealExprRepSqrt & e);

	/// Destructor
	~RealExprRepSqrt ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepSqrt &
	operator=(const RealExprRepSqrt & e);
};


/**
 * @ingroup Expression
 * @class RealExprRepAbs
 * @brief Tree-representation of expressions abs(e)
 */
class RealExprRepAbs : public RealExprRepUnaryOp {
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepAbs (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepAbs (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepAbs (const RealExprRepAbs & e);

	/// Destructor
	~RealExprRepAbs ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepAbs &
	operator=(const RealExprRepAbs & e);
};



/**
 * @ingroup Expression
 * @class RealExprRepPow
 * @brief Tree-representation of expressions e**n
 */
class RealExprRepPow : public RealExprRepUnaryOp
{
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepPow (RealExprRep & e, int n);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepPow (RealExprRep *e, int n);

	/**
 	 * Copy constructor
 	 */
	RealExprRepPow (const RealExprRepPow & e);

	/// Destructor
	~RealExprRepPow ();

	/// Return the exponent
	int exponent() const;

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	void print(std::ostream & os) const;

	RealExprRep *copy() const;
	//@}

private:
	int _n;  // exponent

	/// Copy protection
	RealExprRepPow &
	operator=(const RealExprRepPow & e);
};



/**
 * @ingroup Expression
 * @class RealExprRepLog
 * @brief Tree-representation of expressions log(e)
 */
class RealExprRepLog : public RealExprRepUnaryOp
{
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepLog (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepLog (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepLog (const RealExprRepLog & e);

	/// Destructor
	~RealExprRepLog ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepLog &
	operator=(const RealExprRepLog & e);
};



/**
 * @ingroup Expression
 * @class RealExprRepExp
 * @brief Tree-representation of expressions exp(e)
 */
class RealExprRepExp : public RealExprRepUnaryOp
{
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepExp (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepExp (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepExp (const RealExprRepExp & e);

	/// Destructor
	~RealExprRepExp ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepExp &
	operator=(const RealExprRepExp & e);
};



/**
 * @ingroup Expression
 * @class RealExprRepCos
 * @brief Tree-representation of expressions cos(e)
 */
class RealExprRepCos : public RealExprRepUnaryOp
{
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepCos (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepCos (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepCos (const RealExprRepCos & e);

	/// Destructor
	~RealExprRepCos ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepCos &
	operator=(const RealExprRepCos & e);
};



/**
 * @ingroup Expression
 * @class RealExprRepCosh
 * @brief Tree-representation of expressions cosh(e)
 */
class RealExprRepCosh : public RealExprRepUnaryOp
{
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepCosh (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepCosh (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepCosh (const RealExprRepCosh & e);

	/// Destructor
	~RealExprRepCosh ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepCosh &
	operator=(const RealExprRepCosh & e);
};



/**
 * @ingroup Expression
 * @class RealExprRepACos
 * @brief Tree-representation of expressions acos(e)
 */
class RealExprRepACos : public RealExprRepUnaryOp
{
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepACos (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepACos (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepACos (const RealExprRepACos & e);

	/// Destructor
	~RealExprRepACos ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepACos &
	operator=(const RealExprRepACos & e);
};




/**
 * @ingroup Expression
 * @class RealExprRepACosh
 * @brief Tree-representation of expressions acosh(e)
 */
class RealExprRepACosh : public RealExprRepUnaryOp
{
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepACosh (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepACosh (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepACosh (const RealExprRepACosh & e);

	/// Destructor
	~RealExprRepACosh ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepACosh &
	operator=(const RealExprRepACosh & e);
};


/**
 * @ingroup Expression
 * @class RealExprRepSin
 * @brief Tree-representation of expressions sin(e)
 */
class RealExprRepSin : public RealExprRepUnaryOp
{
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepSin (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepSin (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepSin (const RealExprRepSin & e);

	/// Destructor
	~RealExprRepSin ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepSin &
	operator=(const RealExprRepSin & e);
};


/**
 * @ingroup Expression
 * @class RealExprRepSinh
 * @brief Tree-representation of expressions sinh(e)
 */
class RealExprRepSinh : public RealExprRepUnaryOp
{
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepSinh (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepSinh (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepSinh (const RealExprRepSinh & e);

	/// Destructor
	~RealExprRepSinh ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepSinh &
	operator=(const RealExprRepSinh & e);
};

/**
 * @ingroup Expression
 * @class RealExprRepSin
 * @brief Tree-representation of expressions asin(e)
 */
class RealExprRepASin : public RealExprRepUnaryOp
{
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepASin (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepASin (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepASin (const RealExprRepASin & e);

	/// Destructor
	~RealExprRepASin ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepASin &
	operator=(const RealExprRepASin & e);
};

/**
 * @ingroup Expression
 * @class RealExprRepASinh
 * @brief Tree-representation of expressions asinh(e)
 */
class RealExprRepASinh : public RealExprRepUnaryOp
{
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepASinh (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepASinh (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepASinh (const RealExprRepASinh & e);

	/// Destructor
	~RealExprRepASinh ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepASinh &
	operator=(const RealExprRepASinh & e);
};

/**
 * @ingroup Expression
 * @class RealExprRepTan
 * @brief Tree-representation of expressions tan(e)
 */
class RealExprRepTan : public RealExprRepUnaryOp
{
public:

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepTan (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepTan (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepTan (const RealExprRepTan & e);

	/// Destructor
	~RealExprRepTan ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepTan &
	operator=(const RealExprRepTan & e);
};


/**
 * @ingroup Expression
 * @class RealExprRepTanh
 * @brief Tree-representation of expressions tanh(e)
 */
class RealExprRepTanh : public RealExprRepUnaryOp
{
public:

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepTanh (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepTanh (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepTanh (const RealExprRepTanh & e);

	/// Destructor
	~RealExprRepTanh ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepTanh &
	operator=(const RealExprRepTanh & e);
};



/**
 * @ingroup Expression
 * @class RealExprRepAtan
 * @brief Tree-representation of expressions atan(e)
 */
class RealExprRepATan : public RealExprRepUnaryOp
{
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepATan (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepATan (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepATan (const RealExprRepATan & e);

	/// Destructor
	~RealExprRepATan ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepATan &
	operator=(const RealExprRepATan & e);
};




/**
 * @ingroup Expression
 * @class RealExprRepAtanh
 * @brief Tree-representation of expressions atanh(e)
 */
class RealExprRepATanh : public RealExprRepUnaryOp
{
public:
	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepATanh (RealExprRep & e);

	/**
 	 * Constructor
 	 * @param e sub-term
 	 */
	RealExprRepATanh (RealExprRep *e);

	/**
 	 * Copy constructor
 	 */
	RealExprRepATanh (const RealExprRepATanh & e);

	/// Destructor
	~RealExprRepATanh ();

	/// @name Base class's virtual methods
	//@{
	void visit(RealExprVisitor & v);

	RealExprRep *copy() const;
	//@}

private:
	/// Copy protection
	RealExprRepATanh &
	operator=(const RealExprRepATanh & e);
};



/**
 * @ingroup Expression
 * @class RealExpr
 * @brief Interval expressions
 */
class RealExpr : public SymbolicExpression
{
public:
	/// @name Constructors
	//@{
	RealExpr ();

	RealExpr (RealExprRep & expr);

	RealExpr (RealExprRep *expr);

	//RealExpr (const RealConstant & c);
	//RealExpr (const IntervalConstant & c);
	RealExpr (const Constant & c);

	RealExpr (const int & n);
	RealExpr (const long long & n);

	RealExpr (const double & x);

	RealExpr (Variable & v);

	RealExpr (const RealExpr & e);
	//@}

	/// Destructor
	~RealExpr ();

	/// @name Copy operator
	//@{
	RealExpr &
	operator=(const RealExpr & e);

	//@}

	/**
 	 * Add operator
 	 * @param e the RealExpr to add to this*
 	 * @post this := this + e
 	 */
	RealExpr &
	operator+=(const RealExpr & e);

	/**
 	 * Substraction operator
 	 * @param e the RealExpr to sustract to this*
 	 * @post this := this - e
 	 */
	RealExpr &
	operator-=(const RealExpr & e);

	/**
 	 * Multiplication operator
 	 * @param e the RealExpr to multiply with this*
 	 * @post   this := this * e
 	 */
	RealExpr &
	operator*=(const RealExpr & e);

	/**
 	 * Division operator
 	 * @param e the RealExpr to divide with this*
 	 * @post   this := this / e
 	 */
	RealExpr &
	operator/=(const RealExpr & e);

	/**
 	 * Return a copy of the expression
 	 * @return a copy of *this
 	 */
	RealExpr *copy() const;

	/**
 	 * Return the tree-representation of the expression
 	 * @return the representation of the expression
 	 */
	RealExprRep *rep();

	/**
 	 * Return the tree-representation of the expression
 	 * @return the representation of the expression
 	 */
	RealExprRep *const_rep() const;

	/**
 	 * @brief Get the type of the expression
 	 */
	std::string type() const
	{
		return "RealExpr";
	}
};


//------------------------------------------------------------------------
// Operators
//------------------------------------------------------------------------

/** @relates RealExpr
 * @brief Creation of expression e+f
 */
elisa::RealExpr
operator+(const elisa::RealExpr & e,
          const elisa::RealExpr & f);

/** @relates RealExpr
 * @brief Creation of expression e-f
 */
elisa::RealExpr
operator-(const elisa::RealExpr & e,
          const elisa::RealExpr & f);

/** @relates RealExpr
 * @brief Creation of expression -e
 */
elisa::RealExpr
operator-(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression e*f
 */
elisa::RealExpr
operator*(const elisa::RealExpr & e,
          const elisa::RealExpr & f);

/** @relates RealExpr
 * @brief Creation of expression e/f
 */
elisa::RealExpr
operator/(const elisa::RealExpr & e,
          const elisa::RealExpr & f);

/** @relates RealExpr
 * @brief Creation of expression sqr(e)
 */
elisa::RealExpr sqr(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression sqrt(e)
 */
elisa::RealExpr sqrt(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression e power n
 */
elisa::RealExpr pow(const elisa::RealExpr & e,
                    const int & n);

/** @relates RealExpr
 * @brief Creation of expression log(e)
 */
elisa::RealExpr log(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression exp(e)
 */
elisa::RealExpr exp(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression cos(e)
 */
elisa::RealExpr cos(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression acos(e)
 */
elisa::RealExpr acos(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression sin(e)
 */
elisa::RealExpr sin(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression asin(e)
 */
elisa::RealExpr asin(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression tan(e)
 */
elisa::RealExpr tan(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression atan(e)
 */
elisa::RealExpr atan(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression cosh(e)
 */
elisa::RealExpr cosh(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression acosh(e)
 */
elisa::RealExpr acosh(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression sinh(e)
 */
elisa::RealExpr sinh(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression asinh(e)
 */
elisa::RealExpr asinh(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression tanh(e)
 */
elisa::RealExpr tanh(const elisa::RealExpr & e);

/** @relates RealExpr
 * @brief Creation of expression atanh(e)
 */
elisa::RealExpr atanh(const elisa::RealExpr & e);

END_NAMESPACE_ELISA

#endif // ELISA_REAL_EXPR_H
